// ml278
// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifndef __PLANETARYPLANET_H_
#define __PLANETARYPLANET_H_

#include <vector>
#include <Ogre.h>
#include "planetaryscenemanager.h"
#include "planetaryatmosphere.h"
#include "planetarybody.h"

#include "eventlistener.h"

using namespace ml278;

namespace Ogre
{
	class PlanetaryZone;
	class PlanetaryPage;
	class PlanetaryLoadable;

	/**
	 * Main class for planets.
	 * Holds information about materials, handles paging, creates the six zone of the cube-mapped sphere
	 * making up the planet and creates the atmosphere if necessary.
	*/
	class PlanetaryPlanet : public EventListener, public PlanetaryBody
	{
	public:
		PlanetaryPlanet(PlanetarySceneManager *mgr);
		~PlanetaryPlanet();

		void init();
		void load();
		void unload();
		void uninit();
		
		/** does the planet have an atmosphere?
		 * @returns true if the planet has an atmosphere, false if not
		 */
		bool hasAtmosphere();
		
		/// overridden from EventListener
		bool frameStarted(const FrameEvent &evt);
		/// overridden from EventListener
		bool frameEnded(const FrameEvent &evt);

		/// returns the planets scene node
		inline SceneNode *getSceneNode()
		{
			return mSceneNode;
		}

		/// Update paging of the planet with the current camera
		void updatePaging(Camera *cam);

		/// Adds a loadable to the load queue
		void addLoadableToLoadQueue(PlanetaryLoadable *page);

		/// Inserts a loadable to the front of the load queue
		void insertLoadableToLoadQueue(PlanetaryLoadable *page);

		/// Adds a loadable to the unload queue
		void addLoadableToUnloadQueue(PlanetaryLoadable *page);
		
		/// sets the material used for the ground
		void setGroundMaterial(MaterialPtr &mat);
		/// sets material used for the atmosphere
		void setAtmosphereMaterial(String basename);
		
		const Vector3 getPosition() const
		{
			return(mPosition);
		}

		inline const Real getRadius() const
		{
			return mRadius;
		}
		
		//void setPosition(Vector3 pos);
		
		/// gives the maximum altitude
		inline const Real getMaxAltitude() const
		{
			return mMaxAltitude;
		}
		
		/** gives the minimum altitude in relation to radius
		 * @note for use with atmosphere shader
		 * @return returns a negative number
		 */
		inline const Real getMinAltitude() const
		{
			return mMinAltitude;
		}
		
	private:
		/// Scene Manager object
		PlanetarySceneManager *mSceneMgr;
		
		/// This planet's Scene Node
		SceneNode *mSceneNode;

		/// Each planet has 6 zones
		std::vector<PlanetaryZone *> mZones;
		
		/// Atmosphere object
		PlanetaryAtmosphere *mAtmosphere;

		/// true if the planet is loaded (load() has been run successfully)
		bool mIsLoaded;
		/// true if the planet has been initialised (init() has been run successfully)
		bool mIsInit;
		/// true if the planet has an atmosphere
		bool mHasAtmosphere;
				
		/// The maximum altitude for the given radius and scale
		Real mMaxAltitude;
		/** the minimum altitude for the given radius and scale
		 * @note this is given as a negative for use with radius (used for giving proper info to the atmosphere shader)
		 */
		Real mMinAltitude;
		
		/// Materials for renderables
		MaterialPtr mGroundFromSpace;
		MaterialPtr mGroundFromAtmosphere;
		
		/// Process the current load queues
		void processLoadQueues();

		/// Process the current unload queues
		void processUnloadQueues();

		/// amount of frames since last loading operation, used to avoid overloading the system
		/// by continually loading/unloading.
		unsigned int mFramesSinceLastLoad;

		/// The load queue
		std::deque<PlanetaryLoadable *> mLoadQueue;

		/// The unload queue
		std::deque<PlanetaryLoadable *> mUnloadQueue;
	};
}

#endif
